(function() {
    var Game = {};

    var GAME_WIDTH = 9;
    var GAME_HEIGHT = 9;

    Game.generateField = function() {
        var gameField = new Field(GAME_WIDTH, GAME_HEIGHT);

        var matrix = [];

        for (var row = 0; row < gameField.Height; row++) {

            var rowElements = [];

            for (var col = 0; col < gameField.Width; col++) {
                rowElements[col] = this.factory.produceGem(row, col);
            }

            matrix.push(rowElements);
        }

        gameField.matrix = matrix;
        return gameField;
    };

    Game.factory = new GemFactory();
    Game.renderer = new Renderer();
    Game.field = Game.generateField();

    function AmarkTriplesAroundGem(matrix, point) {

        var i = parseInt(point.Row) - 1;
        var counter = 1;
        var isThereATriple = false;
        //check if it is in the middle of a triple
        if ((point.Row < matrix.length - 1 && matrix[point.Row + 1][point.Col].Color === matrix[point.Row][point.Col].Color &&
                point.Row > 0 && matrix[point.Row - 1][point.Col].Color === matrix[point.Row][point.Col].Color) ||
                ((point.Col < matrix.length - 1 && matrix[point.Row][point.Col + 1].Color === matrix[point.Row][point.Col].Color) &&
                        (point.Col > 0 && matrix[point.Row ][point.Col - 1].Color === matrix[point.Row][point.Col].Color)))
        {
            isThereATriple = true;
        }
        //Check Up
        while (i >= 0) {
            if (matrix[i][point.Col].Color !== matrix[i + 1][point.Col].Color) {
                break;
            }
            counter++;
            i--;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row - j][point.Col].toRemove = true;
            }
            isThereATriple = true;
        }

        //CheckRight
        i = point.Col + 1;
        counter = 1;
        while (i < matrix.length) {
            if (matrix[point.Row][i].Color !== matrix[point.Row][i - 1].Color) {
                break;
            }
            counter++;
            i++;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row][point.Col + j].toRemove = true;
            }
            isThereATriple = true;
        }
        //Check Down
        i = point.Row + 1;
        counter = 1;

        while (i < matrix.length) {
            if (matrix[i][point.Col].Color !== matrix[i - 1][point.Col].Color) {
                break;
            }
            counter++;
            i++;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row + j][point.Col].toRemove = true;
            }
            isThereATriple = true;
        }
        //Check Left
        i = point.Col - 1;
        counter = 1;
        while (i >= 0) {
            if (matrix[point.Row][i].Color !== matrix[point.Row][i + 1].Color) {
                break;
            }
            counter++;
            i--;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row][point.Col - j].toRemove = true;
            }
            isThereATriple = true;
        }

        return isThereATriple;
    }

    function markTriplesAroundGem(matrix, point) {

        var i = parseInt(point.Row) - 1;
        var counter = 1;
        var triples = 0;
        //check if it is in the middle of a triple
        if ((point.Row < matrix.length - 1 && matrix[point.Row + 1][point.Col].Color === matrix[point.Row][point.Col].Color &&
                point.Row > 0 && matrix[point.Row - 1][point.Col].Color === matrix[point.Row][point.Col].Color)) {
            matrix[point.Row + 1][point.Col].toRemove = true;
            matrix[point.Row][point.Col].toRemove = true;
            matrix[point.Row - 1][point.Col].toRemove = true;
            triples = 3;
        }
        else if (((point.Col < matrix.length - 1 && matrix[point.Row][point.Col + 1].Color === matrix[point.Row][point.Col].Color) &&
                (point.Col > 0 && matrix[point.Row][point.Col - 1].Color === matrix[point.Row][point.Col].Color))) {
            matrix[point.Row][point.Col + 1] = true;
            matrix[point.Row][point.Col].toRemove = true;
            matrix[point.Row][point.Col - 1] = true;
            triples = 3;
        }
        //Check Up
        while (i >= 0) {
            if (matrix[i][point.Col].Color !== matrix[i + 1][point.Col].Color) {
                break;
            }
            counter++;
            i--;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row - j][point.Col].toRemove = true;
            }
            triples = counter;
        }

        //CheckRight
        i = point.Col + 1;
        counter = 1;
        while (i < matrix.length) {
            if (matrix[point.Row][i].Color !== matrix[point.Row][i - 1].Color) {
                break;
            }
            counter++;
            i++;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row][point.Col + j].toRemove = true;
            }
            triples = counter;
        }
        //Check Down
        i = point.Row + 1;
        counter = 1;

        while (i < matrix.length) {
            if (matrix[i][point.Col].Color !== matrix[i - 1][point.Col].Color) {
                break;
            }
            counter++;
            i++;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row + j][point.Col].toRemove = true;
            }
            triples = counter;
        }
        //Check Left
        i = point.Col - 1;
        counter = 1;
        while (i >= 0) {
            if (matrix[point.Row][i].Color !== matrix[point.Row][i + 1].Color) {
                break;
            }
            counter++;
            i--;
        }
        if (counter >= 3) {
            for (var j = 0; j < counter; j++) {
                matrix[point.Row][point.Col - j].toRemove = true;
            }
            triples = counter;
        }

        return triples;
    }

    Game.swapGems = function(gem1, gem2) {

        var gem1Type = gem1.classList[1];
        gem1Type = gem1Type.substring(4, gem1Type.length);
        var gem1Coords = gem1.id.split("-");

        var gem2Type = gem2.classList[1];
        gem2Type = gem2Type.substring(4, gem2Type.length);
        var gem2Coords = gem2.id.split("-");

        // Swap possible?

        //var top = (gem1Coords[0] - gem2Coords == -1)
        var isItANeighbourOnLeft = (gem1Coords[0] == gem2Coords[0] && gem1Coords[1] == parseInt(gem2Coords[1]) - 1);
        var isItANeighbourOnRight = (gem1Coords[0] == gem2Coords[0] && gem1Coords[1] == parseInt(gem2Coords[1]) + 1);
        var isItANeigbourDown = (gem1Coords[0] == parseInt(gem2Coords[0]) + 1 && gem1Coords[1] == gem2Coords[1]);
        var isItANeigbourUp = (gem1Coords[0] == parseInt(gem2Coords[0]) - 1 && gem1Coords[1] == gem2Coords[1])
        if (isItANeighbourOnRight ||
                isItANeighbourOnLeft ||
                isItANeigbourDown ||
                isItANeigbourUp) {
            gem1.classList.remove(gem1.classList[1]);
            gem1.classList.add("gem-" + gem2Type);

            gem2.classList.remove(gem2.classList[1]);
            gem2.classList.add("gem-" + gem1Type);

            Game.field.matrix[gem1Coords[0]][gem1Coords[1]].Color = GemColor.parseColor(gem2Type);
            Game.field.matrix[gem2Coords[0]][gem2Coords[1]].Color = GemColor.parseColor(gem1Type);

            var point1 = new Point(parseInt(gem1Coords[0]), parseInt(gem1Coords[1]));
            var point2 = new Point(parseInt(gem2Coords[0]), parseInt(gem2Coords[1]));
            var isThereAtriple1 = markTriplesAroundGem(Game.field.matrix, point1);
            var isThereAtriple2 = markTriplesAroundGem(Game.field.matrix, point2);
            if (!(isThereAtriple1 || isThereAtriple2)) {
                //var top = (gem1Coords[0] - gem2Coords == -1)

                gem2.classList.remove(gem2.classList[1]);
                gem2.classList.add("gem-" + gem2Type);

                gem1.classList.remove(gem1.classList[1]);
                gem1.classList.add("gem-" + gem1Type);

                Game.field.matrix[gem1Coords[0]][gem1Coords[1]].Color = GemColor.parseColor(gem1Type);
                Game.field.matrix[gem2Coords[0]][gem2Coords[1]].Color = GemColor.parseColor(gem2Type);
            }
        }
    };

    var dragged = null;
    var dropped = null;

    Game.onGemClick = function(e) {

        // just see selected element
        e.target.className += ' selected-1';

        if (e.target.className.length === 0) {
            return;
        }

        if (dragged == null) {
            dragged = e.target;
        } else {

            if (dragged == e.target) {
                alert("error!");
                return;
            }

            dropped = e.target;

            Game.swapGems(dragged, dropped);
            dragged = null;
            dropped = null;

            Game.remove();
            Game.renderer.render();

            //var removeCount = Game.checkRemove();
            //while (removeCount)
            //{
            //    Game.remove();
            //    removeCount = Game.checkRemove();
            //    Game.renderer.render();
            //}

            //Game.checkRemove();
            //Game.remove();
            //Game.renderer.render();

        }
    };

    Game.checkRemove = function(direction) {

        for (var row = 0; row < this.field.matrix.length; row++) {
            for (var col = 0; col < this.field.matrix[row].length; col++) {
                markTriplesAroundGem(this.field.matrix, new Point(row, col));
            }
        }
    };

    function dropGems(matrix, row, col) {
        for (var r = row; r > 0; r--) {
            var curr = matrix[r][col];
            var upper = matrix[r - 1][col];

            curr.Color = upper.Color;
        }

        var top = matrix[0][col];
        
        var random = Math.floor((Math.random() * 7) + 1);
        top.Color = random;

        return matrix;
    }

    Game.remove = function() {
        for (var row = 0; row < this.field.matrix.length; row++) {
            for (var col = 0; col < this.field.matrix[row].length; col++) {

                if (this.field.matrix[row][col].toRemove === true) {
                    var removed = this.field.matrix[row][col];

                    this.field.matrix = dropGems(this.field.matrix, row, col);

                    //var upper;

                    //if (row - 1 >= 0) {
                    //    upper = this.field.matrix[row - 1][col];
                    //    removed.Color = upper.Color;
                    //    upper.toRemove = true;
                    //} else {
                    //    removed.Color = GemColor.Orange;
                    //}

                    removed.toRemove = false;
                }
            }
        }

        console.log(this.field.matrix);
    };

    Game.init = function() {
        var wrapper = document.querySelector("#wrapper #gameField");

        wrapper.addEventListener("click", onGemClick);

        this.renderer = new Renderer(this.field, wrapper);
        this.renderer.render();
    };


    //var field =
    //[
    //    [GemColor.Blue, GemColor.Red, GemColor.Green, GemColor.Purple, GemColor.Blue],
    //    [GemColor.Purple, GemColor.Green, GemColor.Yellow, GemColor.Red, GemColor.Green],
    //    [GemColor.Blue, GemColor.Red, GemColor.Green, GemColor.Purple, GemColor.Blue],
    //];

    var render = false;

//    renderField();
//    setInterval(renderField, 800);
    Game.init();

})();